/**
 * Class responsable for managing all accesses to the ontolgy.
 */
package ua.ws.feedsreader.db;

import com.sun.syndication.feed.synd.SyndCategoryImpl;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.openrdf.model.Literal;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.query.BindingSet;
import org.openrdf.query.BooleanQuery;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.QueryLanguage;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import ptstemmer.Stemmer;
import ptstemmer.implementations.PorterStemmer;
import ua.ws.feedsreader.common.FeedEntry;
import ua.ws.feedsreader.common.Prefixes;
import ua.ws.feedsreader.common.User;
import ua.ws.feedsreader.utils.Log;

/**
 * @author ricardo
 *
 */
public class SemanticManager {

    private int idUtilizador = 1;
    private int feedId = 1;

    /*
     * User authentication
     * 
     * @param login - user login
     * @param password - user password
     */
    public User login(String login, String password) throws RepositoryException, QueryEvaluationException, MalformedQueryException {

        RepositoryConnection con = getCon();

        User user = new User();

        //query sparql to check if the user has a valid login
        String queryString = "select ?predicate ?info  { ?user  <http://www.owl-ontologies.com/technology.owl#login> '" + login + "'^^<http://www.w3.org/2001/XMLSchema#string> . "
                + "?user <http://www.owl-ontologies.com/technology.owl#password> '" + password + "'^^<http://www.w3.org/2001/XMLSchema#string> "
                + " . ?user ?predicate ?info . FILTER isLiteral(?info) }";

        TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
        TupleQueryResult tupleResult = tupleQuery.evaluate();

        BindingSet tempBinding;
        //devolve os literals do utilizador (as propriedades dele)
        while (tupleResult.hasNext()) {
            tempBinding = tupleResult.next();
            String predicate = tempBinding.getBinding("predicate").getValue().stringValue();
            String info = tempBinding.getBinding("info").getValue().stringValue();
            switch (predicate) {
                case Prefixes.LOGIN:
                    user.setLogin(info);
                    break;
                case Prefixes.PRIMEIRO_NOME:
                    user.setFirstName(info);
                    break;
                case Prefixes.ULTIMO_NOME:
                    user.setLastName(info);
                    break;
                case Prefixes.EMAIL:
                    user.setEmail(info);
                    break;
                case Prefixes.IDUTILIZADOR:
                    user.setIdUtilizador(Integer.parseInt(info));
                    break;
            }

        }
        con.close();
        if (user.getLogin() != null) {
            return user;
        } else {
            return null;
        }
    }

    /*
     * Register a new user in the system
     * 
     * @param login - user login
     * @param password - user password
     * @param firstName - user's first name
     * @param lastName - user's last name
     * @param email - user's email
     */
    public boolean register(String login, String password, String firstName, String lastName, String email) throws RepositoryException, MalformedQueryException, QueryEvaluationException {

        RepositoryConnection con = getCon();

        // check if the login already exists
        String queryString = "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>"
                + "ASK  { ?x  <http://www.owl-ontologies.com/technology.owl#login> '" + login + "'^^<http://www.w3.org/2001/XMLSchema#string> }";

        BooleanQuery boolQuery = con.prepareBooleanQuery(QueryLanguage.SPARQL, queryString);
        boolean result = boolQuery.evaluate();

        //if not, register the new user
        if (result == false) {

            setIdUtilizador(con);

            ValueFactory f = con.getValueFactory();

            URI subject = f.createURI(Prefixes.TECHNOLOGY + login);

            //adiciona as propriedades
            URI dt = f.createURI("http://www.w3.org/2001/XMLSchema#string");
            Literal lit1 = f.createLiteral(login, dt);
            Literal lit2 = f.createLiteral(password, dt);
            Literal lit3 = f.createLiteral(email, dt);
            Literal lit4 = f.createLiteral(firstName, dt);
            Literal lit5 = f.createLiteral(lastName, dt);
            Literal lit6 = f.createLiteral(getIdUtilizador());


            URI predicate = f.createURI(Prefixes.LOGIN);
            con.add(subject, predicate, lit1);

            predicate = f.createURI(Prefixes.PASSWORD);
            con.add(subject, predicate, lit2);

            predicate = f.createURI(Prefixes.EMAIL);
            con.add(subject, predicate, lit3);

            predicate = f.createURI(Prefixes.PRIMEIRO_NOME);
            con.add(subject, predicate, lit4);

            predicate = f.createURI(Prefixes.ULTIMO_NOME);
            con.add(subject, predicate, lit5);

            predicate = f.createURI(Prefixes.IDUTILIZADOR);
            con.add(subject, predicate, lit6);

            //statement que relaciona tudo com o type utilizador             
            con.add(subject, f.createURI(Prefixes.RDF_TYPE), f.createURI(Prefixes.UTILIZADOR));

            con.close();
            return true;
        }

        return false;

    }

    /*
     * Get all categories that exist in the system. Basically is the classes that exists in the ontology
     *           
     */
    public List<String> getCategories() throws RepositoryException, MalformedQueryException, QueryEvaluationException {

        RepositoryConnection con = getCon();

        List<String> auxVec = new ArrayList<>();
        ValueFactory f = con.getValueFactory();

        String categoria;

        //query that returns all classes that are subclass of technology. Technology is our main class.
        String queryString = "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
                + " SELECT DISTINCT ?categoria "
                + " WHERE { ?categoria <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> rdfs:Class . "
                + "?categoria rdfs:subClassOf <http://www.owl-ontologies.com/technology.owl#tecnologia> } ORDER BY ASC(?categoria)";

        TupleQuery tuple = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString, "http://www.owl-ontologies.com/technology.owl");
        TupleQueryResult result = tuple.evaluate();

        BindingSet categorias;
        while (result.hasNext()) {
            categorias = result.next();
            categoria = categorias.getBinding("categoria").getValue().stringValue().split("#")[1];
            //não deixar ficar a tecnologia, para não "subscrever" todos os filhos à partida
            if (!categoria.equalsIgnoreCase("tecnologia")) {
                auxVec.add(categoria);
            }
        }

        con.close();

        return auxVec;

    }
    /*
     * Get all categories subscribed by the user
     * @param login - user login
     */

    public List<String> getUserCategories(String login) throws RepositoryException {
        List<String> listCategories = new ArrayList<>();
        RepositoryConnection con = getCon();
        ValueFactory f = con.getValueFactory();
        RepositoryResult<Statement> result = con.getStatements(null, f.createURI(Prefixes.SUBSCRITO), f.createURI(Prefixes.TECHNOLOGY + login), true);

        try {
            while (result.hasNext()) {
                Statement st = result.next();
                listCategories.add(st.getSubject().toString().split("#")[1].split("_")[0]);
            }

            con.close();
            return listCategories;
        } finally {
            result.close();
        }

    }
    /*
     * subscribe a category
     * @param login - user's login
     * @param categories - list of categories to subscribe
     */

    public void subscribeCategories(String login, List<String> categories) throws RepositoryException {
        RepositoryConnection con = getCon();
        ValueFactory f = con.getValueFactory();

        for (String cat : categories) {
            con.add(f.createURI(Prefixes.TECHNOLOGY + cat + "_1"), f.createURI(Prefixes.SUBSCRITO), f.createURI(Prefixes.TECHNOLOGY + login));
        }
        con.close();
    }
    /*
     * unsusbcribe a list of categories
     * @param login - user's login
     * @param categories - list of categories to unsubscribe
     */

    public void unsubscribeCategories(String login, List<String> categories) throws RepositoryException {
        RepositoryConnection con = getCon();
        ValueFactory f = con.getValueFactory();

        for (String cat : categories) {
            con.remove(f.createURI(Prefixes.TECHNOLOGY + cat + "_1"), f.createURI(Prefixes.SUBSCRITO), f.createURI(Prefixes.TECHNOLOGY + login));
        }
        con.close();
    }
    /*
     * Get feeds for a category
     * @param category - category to return the feeds
     */

    public Map<Integer, FeedEntry> getCategoryFeeds(String category) throws RepositoryException, MalformedQueryException, QueryEvaluationException {
        RepositoryConnection con = getCon();

        ValueFactory f = con.getValueFactory();
        Map<Integer, FeedEntry> listaFeeds = new HashMap<>();

        String queryString = "PREFIX :<http://www.owl-ontologies.com/technology.owl#>"
                + "select ?feed ?predicado ?info {:" + category + "_1 :topico ?feed . ?feed ?predicado ?info FILTER isLiteral(?info)}";

        TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
        TupleQueryResult result = tupleQuery.evaluate();

        listaFeeds = fillFeeds(result);
        fillFeedCategories(listaFeeds, tupleQuery, result, con);

        con.close();
        return listaFeeds;


    }

    private void fillFeedCategories(Map<Integer, FeedEntry> listaFeeds, TupleQuery tupleQuery, TupleQueryResult result, RepositoryConnection con) throws RepositoryException, QueryEvaluationException, MalformedQueryException {

        String queryString = "";
        ValueFactory f = con.getValueFactory();
        for (Map.Entry<Integer, FeedEntry> entry : listaFeeds.entrySet()) {
            queryString = "PREFIX :<http://www.owl-ontologies.com/technology.owl#>"
                    + " PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>"
                    + " PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#>"
                    + " PREFIX owl:<http://www.w3.org/2002/07/owl#>"
                    + "select ?categoria where { ?x :topico :feed_" + entry.getValue().getFeedId() + " . ?x rdf:type ?categoria . ?categoria rdf:type owl:Class}";
            
            Log.debug("TEEESTE: "+queryString);

            tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
            tupleQuery.setIncludeInferred(false);
            result = tupleQuery.evaluate();

            List<String> listaTemp = new ArrayList<>();
            while (result.hasNext()) {
                listaTemp.add(f.createURI(result.next().getValue("categoria").stringValue()).getLocalName());
            }
            entry.getValue().setListaCategorias(listaTemp);

        }
    }

    public Map<Integer, FeedEntry> search(String search) throws RepositoryException, MalformedQueryException, QueryEvaluationException {

        RepositoryConnection con = getCon();
        StringTokenizer tokenizer = new StringTokenizer(search);
        String token = "";

        while (tokenizer.hasMoreElements()) {
            if (tokenizer.countTokens() > 1) {
                token += tokenizer.nextToken() + " | ";
            } else {
                token += tokenizer.nextToken();
            }
        }

        String queryString = "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> "
                + " SELECT ?feed ?predicado ?info"
                + " WHERE { ?feed <http://www.owl-ontologies.com/technology.owl#titulo> ?title . "
                + " ?feed <http://www.owl-ontologies.com/technology.owl#descricao> ?desc "
                + " FILTER (regex(str(?title), '" + token + "', 'i') || regex(str(?desc),  '" + token + "', 'i'))"
                + " . ?feed ?predicado ?info FILTER isLiteral(?info)}";

        
        TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
        TupleQueryResult result = tupleQuery.evaluate();

        Map<Integer, FeedEntry> listaFeeds = fillFeeds(result);
        fillFeedCategories(listaFeeds, tupleQuery, result, con);
        con.close();
        return listaFeeds;

    }

    private Map<Integer, FeedEntry> fillFeeds(TupleQueryResult result) throws QueryEvaluationException {
        Map<Integer, FeedEntry> listaFeeds = new HashMap<>();

        BindingSet tempBinding;
        while (result.hasNext()) {
            tempBinding = result.next();

            Integer feedsId = Integer.parseInt(tempBinding.getBinding("feed").getValue().toString().split("_")[1]);
            Log.debug("FeedId: "+feedsId);
            FeedEntry feed = listaFeeds.get(feedsId);

            if (feed == null) {
                feed = new FeedEntry();
                feed.setFeedId(feedsId);
            }
            String info = tempBinding.getBinding("info").getValue().stringValue();

            switch (tempBinding.getBinding("predicado").getValue().toString()) {
                case Prefixes.TITULO:
                    feed.setTitulo(info);
                    break;
                case Prefixes.DESCRICAO:
                    feed.setDescricao(info);
                    break;
                case Prefixes.URL:
                    feed.setUrl(info);
                    break;
                case Prefixes.DATE_OF_INSERTION:
                    feed.setDateOfInsertion(info);
                    break;
            }
            listaFeeds.put(Integer.valueOf(feed.getFeedId()), feed);
        }

        return listaFeeds;

    }

    public List<String> getCategoriesSugestion(String categoryName, String login) throws RepositoryException, MalformedQueryException, QueryEvaluationException {

        RepositoryConnection con = getCon();
        List<String> listaCategorias = new ArrayList<>();
        ValueFactory f = con.getValueFactory();

        Log.debug("GET_CATEGORIES_SUGGESTION");

        String queryString = "PREFIX :<http://www.owl-ontologies.com/technology.owl#>"
                + " PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>"
                + " PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
                + " SELECT ?categoria "
                + " WHERE { :" + categoryName + "_1 :subscrito :" + login + " . "
                + " :" + categoryName + "_1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?x . "
                + " ?x <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?categoria }";


        TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
        tupleQuery.setIncludeInferred(false);
        TupleQueryResult result = tupleQuery.evaluate();

        String categoria = "";
        if (result.hasNext()) {
            categoria = result.next().getValue("categoria").stringValue();
            queryString = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>"
                    + " PREFIX :<http://www.owl-ontologies.com/technology.owl#>"
                    + " PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#>"
                    + " select ?categoria"
                    + " where { ?categoria <http://www.w3.org/2000/01/rdf-schema#subClassOf> <" + categoria + "> . "
                    + " Minus {?y :subscrito :" + login + " . ?y rdf:type ?categoria }}";

            tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
            tupleQuery.setIncludeInferred(false);
            result = tupleQuery.evaluate();

            while (result.hasNext()) {
                String categ = f.createURI(result.next().getBinding("categoria").getValue().stringValue()).getLocalName();
                if (!categ.equals(categoria)) {
                    listaCategorias.add(categ);
                }
            }
            return listaCategorias;

        } else {
            return null;
        }

    }

    public Map<Integer, FeedEntry> getFeedsSugestion(String categoryName, String login) throws RepositoryException, MalformedQueryException, QueryEvaluationException {
        RepositoryConnection con = getCon();

        Log.debug("GET_FEEDS_SUGGESTiON");

        String queryString = "PREFIX :<http://www.owl-ontologies.com/technology.owl#>"
                + " PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>"
                + " PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
                + " SELECT ?categoria "
                + " WHERE { :" + categoryName + "_1 :subscrito :" + login + " . "
                + " :" + categoryName + "_1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?x . "
                + " ?x <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?categoria }";

        TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
        tupleQuery.setIncludeInferred(false);
        TupleQueryResult result = tupleQuery.evaluate();

        String categoria = "";
        if (result.hasNext()) {
            categoria = result.next().getValue("categoria").stringValue();
            queryString = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>"
                    + " PREFIX :<http://www.owl-ontologies.com/technology.owl#>"
                    + " PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#>"
                    + " select distinct ?feed ?predicado ?info where { ?x  <http://www.w3.org/2000/01/rdf-schema#subClassOf> <" + categoria + "> . ?cat rdf:type <" + categoria + "> . ?cat :topico ?feed . ?feed ?predicado ?info filter isLiteral(?info)}";

            tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
            tupleQuery.setIncludeInferred(false);
            result = tupleQuery.evaluate();
            Map<Integer, FeedEntry> listaFeeds = fillFeeds(result);
            fillFeedCategories(listaFeeds, tupleQuery, result, con);
            con.close();
            return listaFeeds;
        } else {
            return null;
        }

    }

    public void feedReaded() {
    }

    public int getIdUtilizador() {
        return idUtilizador;
    }

    public void setIdUtilizador(RepositoryConnection con) throws RepositoryException, QueryEvaluationException, MalformedQueryException {
        String queryString = "PREFIX :<http://www.owl-ontologies.com/technology.owl#>"
                + " SELECT ?utilizador ?idUtilizador"
                + " WHERE { ?feed :idUtilizador ?idUtilizador }"
                + " ORDER BY DESC(?idUtilizador) LIMIT 1";

        TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
        TupleQueryResult result = tupleQuery.evaluate();

        if (result.hasNext()) {
            this.idUtilizador = Integer.parseInt(result.next().getValue("idUtilizador").stringValue()) + 1;
        } else {
            this.idUtilizador = 1;
        }
    }

    /*
     * Insert a new Rss Feed Item in the ontology
     * @param title - Feed's title
     * @param description - Feed's description
     * @param dateOfInsertion - actual date
     * @param categories - list of all categories that come with a entry feed
     * @param stopWordList - list of stopwords.
     * 
     */
    public void insertNewFeedItem(String title, String description, String feedUrl, String dateOfInsertion, List categories, List stopWordList) throws Exception {
        RepositoryConnection con = getCon();
        try {

            // valida que não existe nenhuma feedItem com o mesmo url já adicionado ao sistema
            String queryString = "PREFIX feed: <http://www.owl-ontologies.com/technology.owl#>"
                    + "ASK  { ?itemFeed  feed:url '" + feedUrl + "'^^<http://www.w3.org/2001/XMLSchema#string> }";

            BooleanQuery boolQuery = con.prepareBooleanQuery(QueryLanguage.SPARQL, queryString);


            boolean result = boolQuery.evaluate();

            if (result == false) {
                setFeedId(con);
                insertItemFeedToOntology(con, title, description, feedUrl, dateOfInsertion);
                addFeedToCategory(description, categories, con, stopWordList);
            }


        } catch (Exception e1) {
            throw new Exception("Erro a verificar a existência do título");
        }
        con.close();


    }

    /*
     * Insert a new ItemFeed into the ontology
     * @param con - repository connection
     * @param title - feed's title
     * @param description - feed's description 
     * @param feedUrl - feed's url
     * @param dateOfInsertion - actual date
     */
    private void insertItemFeedToOntology(RepositoryConnection con, String title, String description, String feedUrl, String dateOfInsertion) throws Exception {
        String feed_ID_URI = "http://www.owl-ontologies.com/technology.owl#feed_"; //subject
        ValueFactory f = con.getValueFactory();

        //ADICIONA NOVA FEED caso o titulo ja nao exista na ontologia:          

        URI subject = f.createURI(feed_ID_URI + getFeedId());

        URI dt = f.createURI("http://www.w3.org/2001/XMLSchema#string");
        try {
            Literal lit1 = f.createLiteral(title, dt);
            Literal lit2 = f.createLiteral(description, dt);
            Literal lit3 = f.createLiteral(feedUrl, dt);
            Literal lit5 = f.createLiteral(getFeedId());

            URI dt1 = f.createURI("http://www.w3.org/2001/XMLSchema#date");
            Literal lit4 = f.createLiteral(dateOfInsertion, dt1);

            URI predicate = f.createURI(Prefixes.TITULO);
            con.add(subject, predicate, lit1);

            predicate = f.createURI(Prefixes.DESCRICAO);
            con.add(subject, predicate, lit2);

            predicate = f.createURI(Prefixes.URL);
            con.add(subject, predicate, lit3);

            predicate = f.createURI(Prefixes.DATE_OF_INSERTION);
            con.add(subject, predicate, lit4);

            predicate = f.createURI(Prefixes.IDFEED);
            con.add(subject, predicate, lit5);


            con.add(subject, f.createURI(Prefixes.RDF_TYPE), f.createURI(Prefixes.FEED));

        } catch (Exception e) {
            throw new Exception("Erro a inserir novos itemfeeds na ontologia");
        }
    }

    private void addFeedToCategory(String description, List categories, RepositoryConnection con, List stopWordList) throws RepositoryException, MalformedQueryException, QueryEvaluationException {
        Stemmer stem = new PorterStemmer();
        boolean result = false;

        description = cleanDescription(description, stopWordList);
        String categoryName = "";
        String token = null;

        //primeiro verificar se as categorias existem para fazer o triplo <categoria> <topico> <feed>           
        for (int i = 0; i < categories.size(); i++) {
            categoryName = ((SyndCategoryImpl) categories.get(i)).getName().toLowerCase();
            categoryName = normalizeString(categoryName);
            StringTokenizer category = new StringTokenizer(categoryName);

            while (category.hasMoreElements()) {
                categoryName = category.nextElement().toString().toLowerCase();
                result = addTripleByCategory(categoryName, con);

                if (result == false) {
                    addTripleByCategory(stem.getWordStem(categoryName), con);
                }
            }

        }

        //mesmo assim verificar se na descrição é possível construir mais triplos nao repetindo os anteriormente criados. 
        StringTokenizer tokenizer = new StringTokenizer(description);
        while (tokenizer.hasMoreElements()) {
            token = tokenizer.nextElement().toString().toLowerCase();
            token = token.replace("'", "\"");

            result = addTripleByDescription(token, con);
            if (result == false) {
                addTripleByDescription(stem.getWordStem(token), con);
            }
        }
    }

    private String cleanDescription(String description, List stopWordList) {
        String descriptionTemp = "";
        String token;

        //retirar todos os acentos e ç .... normalizar a descrição
        description = normalizeString(description);

        StringTokenizer tokenizer = new StringTokenizer(description);

        while (tokenizer.hasMoreElements()) {
            token = tokenizer.nextElement().toString();
            //verificar se as palavras do titulo estao na lista de stop words
            if (!stopWordList.contains(token)) {
                descriptionTemp += " " + token;
            }
        }

        return descriptionTemp;
    }

    /*     
     * Remove all accents 
     * @param normalize - string that has to have the accents removed
     */
    private String normalizeString(String normalize) {
        normalize = Normalizer.normalize(normalize, Normalizer.Form.NFD);
        normalize = normalize.replaceAll("[^\\p{ASCII}]", "");
        return normalize;

    }

    /*
     * Add a new triple (statement) by a entry feed category
     * @param categoryName - name of the category to check and create a triple
     * @param con - repository connection
     */
    private boolean addTripleByCategory(String categoryName, RepositoryConnection con) throws RepositoryException, MalformedQueryException, QueryEvaluationException {

        boolean result = false;
        ValueFactory f = con.getValueFactory();

        //check if there is a class that has the category has a label.
        String queryString = "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>"
                + "ASK  { ?categoria  <http://www.w3.org/2000/01/rdf-schema#label> '" + categoryName + "'^^<http://www.w3.org/2001/XMLSchema#string> }";

        BooleanQuery boolQuery = con.prepareBooleanQuery(QueryLanguage.SPARQL, queryString);
        String[] category = null;

        try {
            result = boolQuery.evaluate();
            if (result == true) {
                //get the class corresponding to the category name
                queryString = "SELECT ?categoria WHERE {?categoria <http://www.w3.org/2000/01/rdf-schema#label> '" + categoryName + "'^^<http://www.w3.org/2001/XMLSchema#string> }";

                TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
                TupleQueryResult queryResult = tupleQuery.evaluate();

                BindingSet tempBinding;
                while (queryResult.hasNext()) {
                    tempBinding = queryResult.next();
                    category = tempBinding.getBinding("categoria").getValue().stringValue().split("#");
                }

                //get the individual that has is from that type
                queryString = "SELECT ?individuoCategoria WHERE {?individuoCategoria <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.owl-ontologies.com/technology.owl#" + category[1] + "> } LIMIT 1";

                tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
                queryResult = tupleQuery.evaluate();

                //create the triple. Relates a feed to an individual of the corresponding class.
                while (queryResult.hasNext()) {
                    tempBinding = queryResult.next();
                    con.add(f.createURI(tempBinding.getBinding("individuoCategoria").getValue().stringValue()), f.createURI(Prefixes.TOPICO), f.createURI(Prefixes.FEED + "_" + getFeedId()));
                }

            }
        } catch (Exception e) {
            Log.debug("ERRO na função addtriplebycategory");
        }

        return result;
    }

    /*
     * Add a new triple for all terms of the description (in case that triple don't exists)
     * @param token - token to create the triple 
     * @param con - repository connection
     */
    private boolean addTripleByDescription(String token, RepositoryConnection con) throws RepositoryException, MalformedQueryException, QueryEvaluationException {
        boolean result = false;

        ValueFactory f = con.getValueFactory();

        //validate if there is any class corresponding to the token
        String query = "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>"
                + "ASK  { ?categoria  <http://www.w3.org/2000/01/rdf-schema#label> '" + token + "'^^<http://www.w3.org/2001/XMLSchema#string> }";

        BooleanQuery boolQuery = con.prepareBooleanQuery(QueryLanguage.SPARQL, query);


        try {
            result = boolQuery.evaluate();

            if (result == true) {
                //validate if the feed is not yet related to the class/individual
                query = "PREFIX rdfs: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>"
                        + "ASK  { ?categoria  <http://www.owl-ontologies.com/technology.owl#topico> <http://www.owl-ontologies.com/technology.owl#feed_" + getFeedId() + "> }";
                boolQuery = con.prepareBooleanQuery(QueryLanguage.SPARQL, query);

                result = boolQuery.evaluate();

                if (result == false) {
                    //get's the individual that corresponds to the class
                    query = "SELECT ?individuoCategoria WHERE {?individuoCategoria <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.owl-ontologies.com/technology.owl#" + token + "> } LIMIT 1";


                    TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, query);
                    TupleQueryResult tupleResult = tupleQuery.evaluate();

                    BindingSet tempBinding;
                    //creates the triple token - topico - feed
                    while (tupleResult.hasNext()) {
                        tempBinding = tupleResult.next();
                        con.add(f.createURI(tempBinding.getBinding("individuoCategoria").getValue().stringValue()), f.createURI(Prefixes.TOPICO), f.createURI(Prefixes.FEED + "_" + getFeedId()));
                    }

                }

            }
        } catch (Exception e) {
            Log.debug("Erro na função addtriplebydescription");
        }
        return result;
    }

    public int getFeedId() {
        return feedId;
    }

    public void setFeedId(RepositoryConnection con) throws RepositoryException, MalformedQueryException, QueryEvaluationException {
        //ValueFactory f = con.getValueFactory();                

        String queryString = "PREFIX :<http://www.owl-ontologies.com/technology.owl#>"
                + " SELECT ?feed ?idFeed "
                + " WHERE { ?feed :idFeed ?idFeed } "
                + " ORDER BY DESC(?idFeed) LIMIT 1 ";

        TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
        TupleQueryResult result = tupleQuery.evaluate();

        if (!result.hasNext()) {
            this.feedId = 1;
        } else {
            this.feedId = Integer.parseInt(result.next().getValue("idFeed").stringValue()) + 1;
        }

    }

    /*
     * Return repository connection
     */
    private RepositoryConnection getCon() {

        ConnectionManager repository = new ConnectionManager();
        RepositoryConnection con = null;
        try {
            con = repository.getConnection();
        } catch (RepositoryException ex) {
            Log.debug("Erro a obter a conecção");
        }
        return con;
    }
}
